﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Runtime.Remoting.Contexts;
using System.Text;
using System.Threading.Tasks;

namespace _105_反射学习
{
    class Program
    {
        /// <summary>
        /// 程序集s的名称
        /// </summary>
        public static string CurAssemblyName { get; set; } = "105-反射学习"; //一般是项目文件夹名称，或Unity也是
        public static string CurNameSpace { get; set; } = "_105_反射学习";

        static void Main(string[] args)
        {
            ReflectionClass mRF = new ReflectionClass()
            {
                MyProperty1 = "属性1",
                MyProperty2 = "属性2"
            };
            Type myType = mRF.GetType();
            foreach (var item in myType.GetProperties())
            {
                Console.WriteLine("反射获取类属性名称:" + item.Name); //获取属性的名称
                Console.WriteLine("反射获取属性的值:  " + item.GetValue(mRF)); //获取属性的值
            }
            Console.WriteLine(new string('-', 30));


            //TestNotClassify(myType, mRF);
            //TestClassified(myType, mRF);
            TestSonGetType();

            Console.ReadKey();
        }


        #region 利用反射（未归类）：访问 程序集 模块 类型（Type） 类（class）, 以及实例化类 访问其实例化对象成员
        static void TestNotClassify(Type myType, ReflectionClass mRF)
        {
            //获取程序集信息
            string assembleName = "105-反射学习";
            Assembly assembly = Assembly.Load(assembleName);
            Console.WriteLine("程序集的名称:       " + assembly.FullName);
            Console.WriteLine("程序集的位置:       " + assembly.Location);
            Console.WriteLine("程序集需要的CLR版本:" + assembly.ImageRuntimeVersion);
            Console.WriteLine(new string('-', 30));

            //获取模块信息
            Module[] modules = assembly.GetModules();
            foreach (Module item in modules)
            {
                Console.WriteLine("模块名称：  " + item.Name); //模块名称和程序集的名称一样.exe
                //Console.WriteLine("模块全称：" + item.ScopeName);
                //Console.WriteLine("模块全称：" + item.FullyQualifiedName);
                Console.WriteLine("模块版本ID：" + item.ModuleVersionId);
            }
            Console.WriteLine(new string('-', 30));

            //获取类型信息，一个类对应一个类型
            Type[] types = assembly.GetTypes();
            foreach (Type item in types)
            {
                Console.WriteLine("类名称：      " + item.Name);  //其实是类上面的信息
                Console.WriteLine("类命名空间：  " + item.Namespace);
                Console.WriteLine("类完全命名：  " + item.FullName); //全名是 命名空间.类名
                Console.WriteLine("类的关联特性：" + item.Attributes);
                Console.WriteLine("类的GUID：   " + item.GUID);
            }
            Console.WriteLine(new string('-', 30));

            //获取类型成员信息
            Type type = assembly.GetType("_105_反射学习.ReflectionClass");
            //Type type = typeof(ReflectionClass);
            MemberInfo[] mis = type.GetMembers(); //获取公共成员
            foreach (MemberInfo item in mis)
            {
                Console.WriteLine("类成员名称：" + item.Name); //获取了所有公共方法和字段 Method,Property,Field
                Console.WriteLine("类成员类型：" + item.MemberType);
            }
            Console.WriteLine(new string('-', 30));

            //获取方法
            BindingFlags flags = BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance; //枚举的或运算
            MethodInfo[] methods = type.GetMethods(flags);
            foreach (MethodInfo item in methods)
            {
                Console.WriteLine("public类型，不包括积累继承的实例化方法：" + item.Name);
            }
            Console.WriteLine(new string('-', 30));
            BindingFlags flags2 = BindingFlags.NonPublic | BindingFlags.DeclaredOnly | BindingFlags.Instance; //枚举的或运算
            MethodInfo[] methods2 = type.GetMethods(flags2);
            foreach (MethodInfo item in methods2)
            {
                Console.WriteLine("非public类型的实例化方法：" + item.Name);
            }

            //获取属性
            BindingFlags flags3 = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly | BindingFlags.Instance;
            PropertyInfo[] ppts = type.GetProperties(flags3);
            foreach (PropertyInfo item in ppts)
            {
                Console.WriteLine("属性名称：" + item.Name);
            }
            Console.WriteLine(new string('-', 30));

            //实例化对象的3种方法
            string className = assembly.GetTypes().Where(s => s.Name == "ReflectionClass").ToArray()[0].FullName;
            ReflectionClass mRF2 = (ReflectionClass)assembly.CreateInstance(className); //Assemblly程序集.类 的全名实例化对象
            Assembly.Load("105-反射学习").CreateInstance("105-反射学习.RelectionClass");
            ReflectionClass mRF3 = (ReflectionClass)Activator.CreateInstance(type); //根据Type创建实例化对象

            //访问属性，修改属性，调用方法
            Console.WriteLine("修改前的属性：" + type.GetProperty("MyProperty1").GetValue(mRF));
            type.GetProperty("MyProperty1").SetValue(mRF, "修改后的属性1");
            Console.WriteLine("修改后的属性：" + mRF.MyProperty1);
            type.GetMethod("MyPublicFunc").Invoke(mRF, new object[] { "Ladisson利用反射调用了该方法！！" });
        }
        #endregion

        #region 利用反射（归类）：创建对象2种方式；代码获取程序集；反射继承基类的所有子类；修改字段属性值
        static void TestClassified(Type myType, ReflectionClass mRF)
        {
            //创建对象1：Activator.CreateInstance(Type类型, 参数);
            //创建对象2：Assembly.Load(程序集).CreateInstance(命名空间.类名);
            var rfObj1 = Activator.CreateInstance(typeof(ReflectionClass), new object[] { });
            var rfObj2 = Assembly.Load("105-反射学习").CreateInstance("_105-反射学习.Reflection");


            //代码获取程序集，和命名空间，虽然自己是知道的
            GetAssemblies();

            //常用方法1：通过字符串来创建一个类Type,并实例化它
            Type type = GetTypeByName("ReflectionClass");
            var rfObj3 = (ReflectionClass)Activator.CreateInstance(type);
            //Console.WriteLine("++" + rfObj3.MyProperty1);

            //常用方法2：反射出继承自基类的所有子类,
            List<Type> derivedTypes = new List<Type>();
            GetSonClassByBaseclass(typeof(Animal), derivedTypes, CurAssemblyName);
            for (int i = 0; i < derivedTypes.Count; i++)
            {
                Console.WriteLine(derivedTypes[i].FullName); //命名空间.类名
            }

            //常用方法3：访问一个类的所有属性，并给它赋值
            foreach (PropertyInfo item in typeof(ReflectionClass).GetProperties())
            {
                item.SetValue(rfObj3, "反射属性");
                Console.WriteLine("修改属性为：反射属性");
            }
            foreach (PropertyInfo item in typeof(ReflectionClass).GetProperties())
            {
                Console.WriteLine("通过反射访问实例化对象属性：" + item.GetValue(rfObj3));
            }
        }

        /// <summary>
        /// 通过代码获取程序集名称
        /// </summary>
        /// <param name="typeName"></param>
        static void GetAssemblies()
        {
            //返回当前运行程序的程序集
            Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
            foreach (var item in assemblies)
            {
                Console.WriteLine($"程序集全名：{item.FullName}");
                Console.WriteLine("程序集名称：{0}", item.GetName().Name);
                Console.WriteLine(item.GetType().Namespace);
            }
        }

        /// <summary>
        /// 字符串获取类Type
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        static Type GetTypeByName(string name)
        {
            Type result = Type.GetType(string.Format("{0}.{1}", CurNameSpace, name));
            foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) //这样可以跨程序集来搜索类型
            {
                Type temp = Type.GetType(string.Format("{0}.{1}, {2}", CurNameSpace, name, assembly.FullName));
                if (temp != null)
                {
                    return temp;
                }
            }
            return null;
        }


        /// <summary>
        /// 获取继承自Type的所有子类
        /// </summary>
        /// <param name="type"></param>
        static void GetSonClassByBaseclass(Type baseType, List<Type> derivedTypes, string assemblyName)
        {
            Assembly assemble = Assembly.Load(assemblyName);
            Type[] types = assemble.GetTypes();
            foreach (Type item in types)
            {
                if (item.IsClass && !item.IsAbstract && !item.IsInterface && baseType.IsAssignableFrom(item))
                {
                    derivedTypes.Add(item);
                }
            }
        }

        #endregion

        #region 父类声明，子类赋值，的GetType
        static void TestSonGetType()
        {
            Animal dog = new Dog();
            Animal bird = new Bird();
            Console.WriteLine(dog.GetType());         //结果是子类的Type
            Console.WriteLine(bird.GetType());
            Console.WriteLine(typeof(Dog));
            Console.WriteLine(new Dog().GetType());   //实例化对象和类名是同一个Type
        }

        #endregion
    }
}
